from concurrent.futures import ThreadPoolExecutor
import os
import pickle
import subprocess
import threading
import time
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import random
import psutil
import ttkbootstrap as ttk
import re
import logging
import webview


# noinspection PyGlobalUndefined
def get_important_processes():
    """获取重要进程列表。"""
    global important_processes
    if os.path.exists('important_processes.pkl'):
        with open('important_processes.pkl', 'rb') as f:
            important_processes = pickle.load(f)
            logging.info("已加载重要进程列表: (important_processes.pkl)")
    else:
        windows_path = os.path.join(os.getenv('SystemRoot'))
        important_processes = {}

        # 只加入 explorer.exe 和 System32 目录下的 .exe 文件
        for file in os.listdir(os.path.join(windows_path, 'System32')):
            if file.endswith('.exe'):
                file_path = os.path.join(windows_path, 'System32', file)
                important_processes[file] = file_path

        # 确保 explorer.exe 在列表中
        explorer_path = os.path.join(windows_path, 'explorer.exe')
        if 'explorer.exe' not in important_processes and os.path.exists(explorer_path):
            important_processes['explorer.exe'] = explorer_path

        with open('important_processes.pkl', 'wb') as f:
            pickle.dump(important_processes, f)
            logging.info("已获取重要进程并保存其列表(important_processes.pkl)")


def create_symlink(source, link_name):
    """创建一个符号链接。"""
    if os.name != 'nt':
        raise OSError("这个程序只能在Windows上运行")

    command = f'mklink /J "{link_name}" "{source}"'
    logging.info(f"尝试创建符号链接: {link_name} -> {source}")

    try:
        subprocess.run(command, shell=True, check=True)
        print(f"符号链接已创建: {link_name} -> {source}")
        logging.info(f"符号链接已创建: {link_name} -> {source}")
    except subprocess.CalledProcessError as e:
        print(f"创建符号链接时出错: {e}")
        logging.error(f"创建符号链接时出错: {e}")
        raise Exception(f"❗️创建符号链接失败: {e}")


def file_size(file_path):
    """获取单个文件的大小"""
    return os.path.getsize(file_path)


def get_size(start_path, show):
    """计算给定路径的总大小（递归计算所有文件的大小）。"""
    total_size = 0

    def get_size_worker(path):
        nonlocal total_size
        with ThreadPoolExecutor() as executor:
            file_paths = [os.path.join(dirpath, f)
                          for dirpath, _, filenames in os.walk(path)
                          for f in filenames]
            total_size = sum(executor.map(os.path.getsize, file_paths))

    # 启动线程
    count = threading.Thread(target=get_size_worker, args=(start_path,), daemon=True)
    count.start()
    if show:
        logging.info(f"正在计算文件夹大小: {start_path}")
        status_label.config(text=f"🕒 正在计算文件夹大小...")
    # 等待线程结束
    count.join()
    return total_size


def format_size(size):
    """将字节大小转换为合适的单位。"""
    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
        if size < 1024:
            return f"{size:.2f} {unit}"
        size /= 1024
    return f"{size:.2f} PB"


def update_progress_bar(start_size, dest_path):
    """更新进度条的函数。"""
    start_time = time.time()
    last_size = 0
    while True:
        current_size = get_size(dest_path, False)
        progress = (current_size / start_size) * 100
        progress_bar['value'] = min(progress * 1.5, 150)

        elapsed_time = time.time() - start_time
        speed = (current_size - last_size) / elapsed_time if elapsed_time > 0 else 0
        speed_label.config(text=f"🚀 速度: {format_size(speed)}/s")

        if progress > 0:
            remaining_time = (start_size - current_size) / speed if speed > 0 else 0
            remaining_time_label.config(text=f"⏱ 剩余时间: {format_time(remaining_time)}")

        app.update_idletasks()
        if current_size >= start_size:
            break
        time.sleep(0.1)
        last_size = current_size
        start_time = time.time()


def format_time(seconds):
    """将秒数转换为友好的时间格式。"""
    if seconds < 60:
        return f"{int(seconds)}秒"
    elif seconds < 3600:
        return f"{int(seconds // 60)}分钟 {int(seconds % 60)}秒"
    else:
        hours = seconds // 3600
        minutes = (seconds % 3600) // 60
        return f"{int(hours)}小时 {int(minutes)}分钟"


def choose_directory(entry):
    """选择文件夹并在输入框中显示其路径。"""
    folder_selected = filedialog.askdirectory()
    if folder_selected:  # 确保用户选择了文件夹
        entry.delete(0, tk.END)
        entry.insert(0, folder_selected)
        logging.info(f"选择文件夹: {folder_selected}")


def move_starter():
    """开始移动文件夹的函数。"""
    if not running:
        save_running_status(0)
        start_move()
    else:
        messagebox.showerror("错误", "请等待当前操作完成后再进行下一步操作。")


def disk_check(destination_path, source_folder_size):
    """检查磁盘空间是否足够。"""
    # 获取盘符
    destination_drive = os.path.splitdrive(destination_path)[0]
    # 获取目标盘剩余空间
    destination_free_space = psutil.disk_usage(destination_drive).free
    # 计算目标盘剩余空间是否足够（预留源文件夹大小的0.5%）
    if destination_free_space < source_folder_size * 1.005:
        messagebox.showerror("错误",
                             f"目标盘剩余空间不足，请确保目标盘有足够的空间。\n目标盘剩余空间: {format_size(destination_free_space)}")
        logging.error(f"目标盘剩余空间不足: {destination_free_space} < {source_folder_size * 1.005}")
        return False
    logging.info(f"源文件夹大小: {source_folder_size} 字节，目标盘剩余空间: {destination_free_space} 字节")
    return True


def start_move():
    """开始移动文件夹的函数，并启动进度更新线程。"""
    global running
    running = True
    source = source_entry.get()
    destination = destination_entry.get()
    folder_name = os.path.basename(source)
    dest_folder = os.path.join(destination, folder_name)
    save_moving(source, dest_folder, None, 0)
    # 检查源路径和目标路径的包含关系
    try:
        source_real = os.path.realpath(source)
        dest_real = os.path.realpath(dest_folder)

        if source_real == dest_real:
            messagebox.showerror("错误", "❌源路径和目标路径相同！")
            status_label.config(text="⏳ 等待开始...")
            save_moving(source, dest_folder, "源路径和目标路径相同", 0)
            save_running_status(200)
            running = False
            return

        if source_real.startswith(dest_real + os.sep):
            messagebox.showerror("错误", "源路径是目标路径的子文件夹！")
            status_label.config(text="⏳ 等待开始...")
            save_moving(source, dest_folder, "源路径是目标路径的子文件夹", 0)
            save_running_status(200)
            running = False
            return

        if dest_real.startswith(source_real + os.sep):
            messagebox.showerror("错误", "目标路径是源路径的子文件夹！")
            status_label.config(text="⏳ 等待开始...")
            save_moving(source, dest_folder, "目标路径是源路径的子文件夹", 0)
            save_running_status(200)
            running = False
            return

    except Exception as e:
        logging.error(f"路径解析错误: {e}")
        messagebox.showerror("错误", "路径解析出错，请检查路径是否有效")
        status_label.config(text="⏳ 等待开始...")
        save_moving(source, dest_folder, "路径解析出错", 0)
        save_running_status(200)
        running = False
        return

    if not folder_name:
        messagebox.showerror("错误", "无法移动完整磁盘，请选择文件夹！")
        status_label.config(text="⏳ 等待开始...")
        save_moving(source, dest_folder, "收到错误参数：纯盘符。", 0)
        save_running_status(200)
        running = False
        return

    if not source or not destination:
        messagebox.showerror("错误", "请指定源路径和目标路径")
        status_label.config(text="⏳ 等待开始...")
        save_moving(source, dest_folder, "未指定源路径或目标路径", 0)
        save_running_status(200)
        running = False
        return

    if not os.path.isdir(source):
        messagebox.showerror("错误", "源路径不存在!或无法访问。")
        logging.error(f"源路径不存在或无法访问: {source}")
        status_label.config(text="⏳ 等待开始...")
        save_moving(source, dest_folder, "源路径不存在或无法访问", 0)
        save_running_status(200)
        running = False
        return

    if os.path.exists(dest_folder):
        messagebox.showerror("错误", f"目标文件夹{dest_folder}非空!")
        logging.error(f"目标文件夹非空: {dest_folder}")
        status_label.config(text="⏳ 等待开始...")
        save_moving(source, dest_folder, "目标文件夹非空", 0)
        save_running_status(200)
        running = False
        return

    start_size = get_size(source, True)

    if not disk_check(dest_folder, start_size):
        messagebox.showerror("错误", "磁盘空间不足，请确保目标盘有足够的空间。")
        status_label.config(text="⏳ 等待开始...")
        save_moving(source, dest_folder, "磁盘空间不足", 0)
        save_running_status(200)
        running = False
        return

    logging.info(f"开始移动文件夹: {source} 到 {dest_folder}，总大小: {start_size} 字节")

    threading.Thread(target=move_folder, args=(source, dest_folder), daemon=True).start()
    threading.Thread(target=update_progress_bar, args=(start_size, dest_folder), daemon=True).start()


def get_occupied_process_ids(folder_path):
    """获取占用指定文件夹的进程ID列表。"""
    try:
        result = subprocess.run(
            ['./Handle/handle.exe', folder_path],
            capture_output=True,
            text=True,
            check=True
        )
        output = result.stdout
        process_ids = set(re.findall(r'pid:\s*(\d+)', output))
        logging.info(f"获取占用进程ID成功: {process_ids}")
        return list(process_ids)
    except subprocess.CalledProcessError as e:
        logging.error(f"获取占用进程ID失败: {e}")
        raise Exception(f"获取占用进程ID失败: {e}")


# noinspection PyGlobalUndefined
def force_unlock_folder(source):
    """强制解除文件夹锁定。"""
    for i in range(33):
        handles = get_occupied_process_ids(source)
        if handles:
            global important_processes
            # 获取进程信息
            result = [subprocess.run(f'tasklist /fi "pid eq {pid}"', shell=True, text=True,
                                     capture_output=True).stdout.strip() for pid in handles]
            # 将输出的字符串拆分成多行
            results = [line.split('\n') for line in result]
            # 初始化一个列表来存储解析后的进程信息
            parsed_results = []

            for lines in results:
                for line in lines:
                    # 使用正则表达式匹配进程名称和 PID
                    match = re.match(r'^(.*?)\s+(\d+)\s+', line)
                    if match:
                        name, pid = match.groups()
                        if name != '映像名称':
                            parsed_results.append({'映像名称': name, 'pid': pid})

            # 检查是否有重要进程占用文件夹
            important_processes_in_use = [process for process in parsed_results if
                                          process['映像名称'] in important_processes]
            if important_processes_in_use:
                logging.warning(f"检测到重要进程占用文件夹: {important_processes_in_use}")
                if messagebox.askyesno("注意",
                                       f"检测到其中有重要进程，如需继续（我们将强制关闭后重启一部分进程），请选择是。\n\n"
                                       f"占用重要进程详细信息: {important_processes_in_use}"):
                    # 关闭重要进程
                    for process in important_processes_in_use:
                        subprocess.run(f'taskkill /f /pid {process["pid"]}', shell=True)
                        logging.warning(f"强制关闭重要进程: pid :{process['pid']}, 详细信息:{process['映像名称']}")
                        # 重启重要进程
                        exe_path = important_processes[process['映像名称']]
                        subprocess.run(f'{exe_path}', shell=True, check=False)
                        logging.info(
                            f"尝试重启重要进程: pid :{process['pid']}, 详细信息:{process['映像名称']}，路径: {exe_path}")
                else:
                    return False

            # 过滤掉已关闭的重要进程
            non_important_processes = [process for process in parsed_results if
                                       process['映像名称'] not in important_processes]
            handles = [process['pid'] for process in non_important_processes]
            if handles:
                ask = messagebox.askyesno("注意",
                                          f"检测到源文件夹上有其他进程正在使用，是否强制关闭？\n"
                                          f"我们建议您手动关闭相关程序，如确认可直接关闭或您无法关闭相关程序，请选择是。\n\n"
                                          f"占用进程详细信息: {non_important_processes}")
                if ask:
                    for pid in handles:
                        # 关闭一般进程
                        subprocess.run(f'taskkill /f /pid {pid}', shell=True, check=True)
                        logging.info(
                            f"强制关闭进程: pid :{pid}, 详细信息: {non_important_processes[handles.index(pid)]}")
                    logging.info(f"强制关闭进程完毕: {handles}")
                    handles = get_occupied_process_ids(source)
                    if handles:
                        messagebox.showerror("错误", "解除文件锁定失败，请手动关闭程序后重试。")
                        logging.error("解除文件锁定失败，请手动关闭程序后重试。")
                        return False
                else:
                    return False
            return True
        else:
            return True
    return False


def move_folder(source, destined):
    """使用管理员权限通过CMD移动文件夹的函数。"""
    global running
    source = source.replace('/', '\\')
    destined = destined.replace('/', '\\')
    save_moving(source, destined, None, 0)
    try:
        if not force_unlock_folder(source):
            save_moving(source, destined, "解除文件锁定失败", 0)
            raise Exception("无法解除文件锁定，请手动关闭相关程序后重试。")

        status_label.config(text="🕒 正在获取文件夹所有权...")
        subprocess.run(f'takeown /r /f "{source}"', shell=True, check=True)
        os.makedirs(destined, exist_ok=True)

        status_label.config(text="🕓 正在复制文件夹...")
        save_moving(source, destined, None, 1)
        copy_command = f'xcopy /e /y /q /v /h "{source}" "{destined}"'
        copy_process = subprocess.run(copy_command, shell=True, check=True, stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE)

        if copy_process.returncode == 0:
            save_moving(source, destined, None, 2)
            status_label.config(text="🕔 正在删除源文件夹...")
            if force_unlock_folder(source):
                delete_command = f'rmdir /s /q "{source}"'
                delete_process = subprocess.run(delete_command, shell=True, check=True, stdout=subprocess.PIPE,
                                                stderr=subprocess.PIPE)
                if delete_process.returncode == 0 and not os.path.exists(source):
                    status_label.config(text="🕕 正在创建符号链接...")
                    try:
                        create_symlink(destined, source)
                    except Exception as e:
                        status_label.config(text="创建符号链接失败！")
                        logging.error(f"创建符号链接失败: {e}")
                        save_moving(source, destined, e, 2)
                    status_label.config(text="✔️ 文件夹移动完成")
                    save_moving(source, destined, None, 3)
                    save_running_status(200)
                    messagebox.showinfo("完成", "✔️ 文件夹移动完成")
                    logging.info("文件夹移动完成")
                else:
                    raise Exception("删除源文件夹失败，请手动删除后重试。")
            else:
                save_moving(source, destined, "解除源文件夹锁定失败", 2)
                raise Exception("解除源文件夹锁定失败，请手动关闭相关程序后重试。")
        else:
            save_moving(source, destined, "复制文件夹失败", 1)
            raise Exception(copy_process.stderr)

    except Exception as e:
        messagebox.showerror("错误", str(e))
        status_label.config(text="⏳ 等待开始...")
        logging.error(f"移动失败: {str(e)}")
    finally:
        running = False


def close_window():
    """关闭窗口的函数，询问用户确认是否关闭。"""
    if running and not messagebox.askyesno("请确定", "检测到您正在移动文件，建议您不要退出程序。\n\n是否确认退出？"):
        return
    logging.info("程序已关闭")
    app.destroy()


def situation():
    """在启动时读取上次运行情况，以便错误恢复。"""
    try:
        with open('last_running_status.pkl', 'rb') as f:
            last_running_status = pickle.load(f)
        if last_running_status == 200:
            logging.info("上次运行无误，程序正常启动。")
            pass
        if last_running_status == 0:
            logging.warning(f"上次运行有误，程序状态异常，即将进行撤销。")
            tk.messagebox.showwarning(title="恢复", message=f"检测到程序上次运行时出现错误，即将进行撤销。")
            save_running_status(200)
            try:
                with open('moving.pkl', 'rb') as f:
                    moving = pickle.load(f)
            except FileNotFoundError:
                logging.error("撤销失败，未找到上次迁移记录文件。")
                tk.messagebox.showerror("错误", "撤销失败，未找到上次迁移记录文件。撤销操作无法完成。")
                return
            cancel(moving)
    except FileNotFoundError:
        logging.info(f"无上次运行记录文件。请到此处查阅日志: {os.path.abspath('./file_migration.log')}")
        save_running_status(200)


def save_moving(source, destined, mistake, step):
    """保存迁移记录。"""
    with open('moving.pkl', 'wb') as f:
        pickle.dump({'source': source, 'destined': destined, 'mistake': mistake, 'step': step}, f)
    logging.info(f"保存迁移记录: {source}, {destined}, {mistake}, {step}")


def save_running_status(status):
    """保存运行状态。"""
    with open('last_running_status.pkl', 'wb') as f:
        pickle.dump(status, f)
    logging.info(f"保存运行状态: {status}")


def cancel(moving):
    """撤销出现错误的迁移"""
    # 先显示确认窗口
    confirm_window = tk.Toplevel(app)
    confirm_window.grab_set()
    confirm_window.title("撤销迁移确认")
    confirm_window.iconbitmap('./icon.ico')
    confirm_window.attributes('-topmost', True)

    # 显示错误信息
    ttk.Label(confirm_window,
             text="检测到上次迁移未完成，请确认是否撤销",
             font=("楷体", 15)).grid(row=0, columnspan=2, pady=10)

    # 创建文本框显示详细信息
    text_box = tk.Text(confirm_window, height=10, width=50)
    text_box.grid(row=1, columnspan=2, padx=10)

    l_source = moving['source']
    l_destined = moving['destined']
    l_mistake = moving['mistake']
    l_step = moving['step']

    # 填充详细信息
    text_box.insert(tk.END, f"● 源文件夹位置: {l_source}\n")
    text_box.insert(tk.END, f"● 目标文件夹位置: {l_destined}\n")
    text_box.insert(tk.END, f"● 错误原因: {l_mistake if l_mistake else '未知'}\n")
    text_box.insert(tk.END, f"● 失败阶段: {['准备阶段','复制阶段','删除阶段'][l_step]}\n")
    text_box.config(state=tk.DISABLED)

    # 确认按钮框架
    btn_frame = ttk.Frame(confirm_window)
    btn_frame.grid(row=2, columnspan=2, pady=10)

    def start_cancel():
        confirm_window.destroy()
        show_cancel_progress(moving)


    ttk.Button(btn_frame, text="确认撤销", command=start_cancel,
              bootstyle="danger", width=15).pack(side=tk.LEFT, padx=5)
    ttk.Button(btn_frame, text="取消", command=confirm_window.destroy,
              bootstyle="secondary", width=15).pack(side=tk.LEFT, padx=5)


def show_cancel_progress(moving):
    """显示撤销进度窗口"""
    progress_window = tk.Toplevel(app)
    progress_window.grab_set()
    progress_window.title("正在撤销迁移...")
    progress_window.iconbitmap('./icon.ico')
    progress_window.attributes('-topmost', True)
    progress_window.resizable(False, False)

    # 进度框架
    main_frame = ttk.Frame(progress_window)
    main_frame.pack(padx=20, pady=20)

    ttk.Label(main_frame, text="正在撤销迁移操作...", font=("楷体", 14)).grid(row=0, columnspan=2)

    # 进度条
    progress_var = tk.DoubleVar()
    progress_bar = ttk.Progressbar(main_frame, variable=progress_var,
                                  maximum=100, length=300, mode='determinate')
    progress_bar.grid(row=1, columnspan=2, pady=10)

    # 状态标签
    status_label = ttk.Label(main_frame, text="准备中...")
    status_label.grid(row=2, columnspan=2)

    # 速度/剩余时间标签
    speed_label = ttk.Label(main_frame, text="🚀 速度: -")
    speed_label.grid(row=3, column=0)
    time_label = ttk.Label(main_frame, text="⏱ 剩余时间: -")
    time_label.grid(row=3, column=1)

    # 启动撤销线程
    threading.Thread(target=perform_cancel,
                    args=(moving, progress_var, status_label, speed_label, time_label, progress_window),
                    daemon=True).start()


def perform_cancel(moving, progress_var, status_label, speed_label, time_label, window):
    """实际执行撤销操作"""
    try:
        l_step = moving['step']
        src = moving['source']
        dst = moving['destined']

        def update_gui(value, status, speed="-", remain="-"):
            progress_var.set(value)
            status_label.config(text=status)
            speed_label.config(text=f"🚀 速度: {speed}")
            time_label.config(text=f"⏱ 剩余时间: {remain}")
            window.update()

        # 阶段0：准备阶段失败（可能创建了空目标目录）
        if l_step == 0:
            if os.path.exists(dst):
                update_gui(0, "正在删除残留目录...")
                subprocess.run(f'rmdir /s /q "{dst}"', shell=True, check=True)
            update_gui(100, "✔️ 清理完成", "完成", "0秒")

        # 阶段1：复制过程中失败
        elif l_step == 1:
            def track_delete():
                if not os.path.exists(dst):
                    update_gui(100, "目标文件夹不存在")
                    return

                total_size = get_size(dst, False)
                start_time = time.time()

                # 启动删除线程
                def delete_task():
                    try:
                        subprocess.run(f'rmdir /s /q "{dst}"', shell=True, check=True)
                    except subprocess.CalledProcessError as e:
                        logging.error(f"删除失败: {str(e)}")

                threading.Thread(target=delete_task, daemon=True).start()

                # 跟踪删除进度
                while os.path.exists(dst):
                    current_size = get_size(dst, False)
                    progress = ((total_size - current_size) / total_size) * 100
                    speed = (total_size - current_size) / (time.time() - start_time + 0.001)
                    update_gui(progress, "删除不完整副本...",
                             f"{format_size(speed)}/s",
                             format_time(current_size/speed if speed else 0))
                    time.sleep(0.3)
                update_gui(100, "✔️ 清理完成")

            if os.path.exists(dst):
                if not force_unlock_folder(dst):
                    messagebox.showerror("错误", "无法解除目标文件夹锁定，请手动处理！")
                    return
                threading.Thread(target=track_delete, daemon=True).start()
            else:
                update_gui(100, "目标文件夹不存在")

        # 阶段2：删除源文件失败（此时目标副本完整）
        elif l_step == 2:
            # 清理残留源目录
            if os.path.exists(src):
                force_unlock_folder(src)
                subprocess.run(f'rmdir /s /q "{src}"', shell=True, check=True)

            if not os.path.exists(dst):
                update_gui(100, "目标副本不存在，无法恢复")
                return

            total_size = get_size(dst, False)
            start_time = time.time()

            # 启动恢复线程
            def restore_task():
                try:
                    subprocess.run(f'xcopy /e /y /q /h /i "{dst}" "{src}"',
                                   shell=True, check=True)

                except subprocess.CalledProcessError as e:
                    logging.error(f"恢复失败: {str(e)}")

            threading.Thread(target=restore_task, daemon=True).start()

            # 跟踪恢复进度
            while True:
                if not os.path.exists(src):
                    time.sleep(0.5)
                    continue

                current_size = get_size(src, False)
                progress = (current_size / total_size) * 100
                speed = current_size / (time.time() - start_time + 0.001)
                update_gui(progress, "恢复源文件中...",
                         f"{format_size(speed)}/s",
                         format_time((total_size - current_size)/speed if speed else 0))
                if current_size >= total_size:
                    break

            # 删除目标副本
            if os.path.exists(dst):
                subprocess.run(f'rmdir /s /q "{dst}"', shell=True, check=True)
            update_gui(100, "✔️ 恢复完成")

        window.destroy()
        messagebox.showinfo("完成", "✔️ 撤销操作已成功完成")

    except subprocess.CalledProcessError as e:
        window.destroy()
        error_msg = f"命令行执行失败: {e.stderr.decode('gbk')}" if e.stderr else str(e)
        messagebox.showerror("撤销失败", f"执行系统命令时出错:\n{error_msg}")
    except Exception as e:
        window.destroy()
        messagebox.showerror("撤销失败", f"发生意外错误:\n{str(e)}")


def about():
    """创建关于窗口并显示相关信息。"""
    webview.create_window('关于', 'https://www.xiaowutu.top/Little-Wu-Tu-File-Transfer-System')
    webview.start(icon='./icon.ico')


if __name__ == '__main__':
    try:
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            filename='file_migration.log',
            encoding='utf-8'
        )
    except ValueError:
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            filename='file_migration.log',
        )
    logging.info("程序启动")
    running = False
    get_important_processes()
    tem = ["superhero", "vapor", "cyborg", "solar", "cosmo", "flatly", "journal", "litera", "minty", "pulse", "morph"]
    app = ttk.Window(themename=tem[random.randint(0, 10)])
    app.protocol('WM_DELETE_WINDOW', close_window)
    app.iconbitmap('./icon.ico')
    app.geometry('800x400')
    app.resizable(True, True)
    app.minsize(800, 390)
    app.title('小於菟文件迁移系统')

    # 配置网格布局权重
    app.grid_columnconfigure(0, weight=1)
    app.grid_columnconfigure(1, weight=1)
    app.grid_rowconfigure(5, weight=1)  # 主扩展区域

    # 标题（保持顶部居中）
    ttk.Label(app, text="小於菟文件迁移系统", font=('楷体', 30)).grid(
        row=0, column=0, columnspan=2, pady=10, sticky="n"
    )

    # 源文件夹选择（带弹性扩展）
    source_entry = ttk.Entry(app)
    source_entry.grid(row=1, column=0, sticky="ew", padx=5, pady=5)
    ttk.Button(app, text="📁 选择源文件夹", command=lambda: choose_directory(source_entry),
              bootstyle="outline").grid(row=1, column=1, sticky="ew", padx=5, pady=5)

    # 目标文件夹选择（带弹性扩展）
    destination_entry = ttk.Entry(app)
    destination_entry.grid(row=2, column=0, sticky="ew", padx=5, pady=5)
    ttk.Button(app, text="📁 选择目标文件夹", command=lambda: choose_directory(destination_entry),
              bootstyle="outline").grid(row=2, column=1, sticky="ew", padx=5, pady=5)

    # 操作按钮（全宽扩展）
    ttk.Button(app, text="⚡️ 开始迁移并设置符号链接 ⚡️", command=move_starter,
              bootstyle="outline").grid(row=3, column=0, columnspan=2, sticky="ew", padx=5, pady=5)

    # 进度条容器（整合状态信息）
    lf = ttk.Labelframe(app, text="ℹ️ 移动进度")
    lf.grid(row=5, column=0, columnspan=2, sticky="nsew", padx=5, pady=5)

    # 进度条区域布局配置
    lf.grid_columnconfigure(0, weight=1)
    lf.grid_rowconfigure(1, weight=1)  # 状态信息区域可扩展

    # 进度条（水平填充）
    progress_bar = ttk.Progressbar(lf, mode='determinate', maximum=150, bootstyle="striped")
    progress_bar.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)

    # 状态信息容器（垂直扩展）
    status_frame = ttk.Frame(lf)
    status_frame.grid(row=1, column=0, sticky="nsew", padx=5, pady=5)

    # 状态信息标签（居中）
    status_label = ttk.Label(status_frame, text="⏳ 等待开始...", font=("楷体", 12), anchor="center")
    status_label.pack(fill="x", expand=False)

    speed_label = ttk.Label(status_frame, text="🚀 移动速度: 0 B/s", font=("楷体", 12), anchor="center")
    speed_label.pack(fill="x", expand=False)

    remaining_time_label = ttk.Label(status_frame, text="⏱ 剩余时间: ---", font=("楷体", 12), anchor="center")
    remaining_time_label.pack(fill="x", expand=False)

    # 其他功能按钮
    ttk.Button(app, text="❓ 程序说明 ❓", command=about,
              bootstyle="outline").grid(row=4, column=0, columnspan=2, sticky="ew", padx=5, pady=5)

    situation()
    app.mainloop()
